package com.tools.common.io;

import com.tools.common.object.Note;

import java.io.*;

/**
 * 阻塞 IO 字符流拷贝操作包装类
 * */
@Note("阻塞 IO 字符流拷贝操作包装类")
public final class CharIOCopyBean {

    @Note("源数据，字符输入流")
    private Reader reader;

    @Note("数据存放的目标，字符输出流")
    private Writer writer;

    private int bufferSize;

    /* *******************************************************************************************
     *
     *          构造器
     *
     * *******************************************************************************************
     * */

    public CharIOCopyBean() {}

    public static CharIOCopyBean of() {
        return new CharIOCopyBean();
    }

    /* *******************************************************************************************
     *
     *          Getter / Setter
     *
     * *******************************************************************************************
     * */

    public Reader getReader() {
        return reader;
    }

    public BufferedReader getBufferedReader() {
        try {
            return (reader instanceof BufferedReader)
                    ? (BufferedReader) reader
                    : (bufferSize <= 0) ? new BufferedReader(reader) : new BufferedReader(reader, bufferSize);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setReader(Reader reader) {
        if(reader == null) {
            this.closeAll();
            throw new NullPointerException();
        }
        this.reader = reader;
    }

    public void setReader(InputStream input) {
        try {
            if(input == null) throw new NullPointerException();
            this.reader = IOKit.inputStreamReader(input);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setReader(InputStream input, CharsetEnum charset) {
        try {
            if(input == null) throw new NullPointerException();
            if(charset == null) throw new NullPointerException();
            this.reader = IOKit.inputStreamReader(input, charset);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setReader(File inFile) {
        try {
            if(inFile == null) throw new NullPointerException();
            this.reader = IOKit.fileReader(inFile);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setReader(String inPath) {
        try {
            if(inPath == null || inPath.isEmpty()) throw new NullPointerException();
            this.reader = IOKit.fileReader(inPath);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public Writer getWriter() {
        return writer;
    }

    public BufferedWriter getBufferedWriter() {
        try {
            return (writer instanceof BufferedWriter)
                    ? (BufferedWriter) writer
                    : (bufferSize <= 0) ? new BufferedWriter(writer) : new BufferedWriter(writer, bufferSize);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setWriter(Writer writer) {
        if(writer == null) {
            this.closeAll();
            throw new NullPointerException();
        }
        this.writer = writer;
    }

    public void setWriter(OutputStream output) {
        try {
            if(output == null) throw new NullPointerException();
            this.writer = IOKit.outputStreamWriter(output);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setWriter(OutputStream output, CharsetEnum charset) {
        try {
            if(output == null) throw new NullPointerException();
            if(charset == null) throw new NullPointerException();
            this.writer = IOKit.outputStreamWriter(output, charset);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setWriter(File outFile) {
        this.setWriter(outFile, false);
    }

    public void setWriter(File outFile, boolean append) {
        try {
            if(outFile == null) throw new NullPointerException();
            this.writer = IOKit.fileWriter(outFile, append);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setWriter(String outPath) {
        this.setWriter(outPath, false);
    }

    public void setWriter(String outPath, boolean append) {
        try {
            if(outPath == null || outPath.isEmpty()) throw new NullPointerException();
            this.writer = IOKit.fileWriter(outPath, append);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public int getBufferSize() {
        return bufferSize;
    }

    public void setBufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
    }

    @Override
    public String toString() {
        return "CharIOCopyBean{" +
                "reader=" + reader +
                ", writer=" + writer +
                ", bufferSize=" + bufferSize +
                '}';
    }

    public boolean initReader() {
        return reader != null;
    }

    public boolean initWriter() {
        return writer != null;
    }

    public boolean enableCopy() {
        return reader != null && writer != null;
    }

    public int getBufferSizeOrReplace(int bufferSize) {
        return (this.bufferSize <= 0) ? bufferSize : this.bufferSize;
    }

    public void closeReader() {
        IOKit.close(reader);
        reader = null;
    }

    public void closeWriter() {
        IOKit.close(writer);
        writer = null;
    }

    public void closeAll() {
        closeReader();
        closeWriter();
    }

    public void copy() {
        IOKit.copy(this);
    }

    /* *******************************************************************************************
     *
     *          链式调用
     *
     * *******************************************************************************************
     * */

    public CharIOCopyBean reader(Reader inputStream) {
        this.setReader(inputStream);
        return this;
    }

    public CharIOCopyBean reader(InputStream input) {
        this.setReader(input);
        return this;
    }

    public CharIOCopyBean reader(InputStream input, CharsetEnum charset) {
        this.setReader(input, charset);
        return this;
    }

    public CharIOCopyBean reader(File inFile) {
        this.setReader(inFile);
        return this;
    }

    public CharIOCopyBean reader(String inPath) {
        this.setReader(inPath);
        return this;
    }

    public CharIOCopyBean writer(Writer writer) {
        this.setWriter(writer);
        return this;
    }

    public CharIOCopyBean writer(OutputStream output) {
        this.setWriter(output);
        return this;
    }

    public CharIOCopyBean writer(OutputStream output, CharsetEnum charset) {
        this.setWriter(output, charset);
        return this;
    }

    public CharIOCopyBean writer(File outPath) {
        this.setWriter(outPath);
        return this;
    }

    public CharIOCopyBean writer(File outPath, boolean append) {
        this.setWriter(outPath, append);
        return this;
    }

    public CharIOCopyBean writer(String outPath) {
        this.setWriter(outPath);
        return this;
    }

    public CharIOCopyBean writer(String outPath, boolean append) {
        this.setWriter(outPath, append);
        return this;
    }

    public CharIOCopyBean bufferSize(int bufferSize) {
        this.setBufferSize(bufferSize);
        return this;
    }
}
